﻿using System;
using System.Collections.Generic;
using System.Linq;

using BEX.DataAccess;
using BEX.Core;
using BEX.Core.Exchange;

namespace BEX.RuleMonitor
{


    /// <summary>
    /// Catch the condition where the trade price has crossed a flat amount value.  Time is not a factor.  Only Previous Tick vs. Current Tick.
    ///
    /// </summary>
    public class FlatAmountRule : AlertRule
    {
        public int Amount { get; set; }

        public FlatAmountRule()
        {
        }

        public FlatAmountRule(ExchangeType exchange, CurrencyType basec, CurrencyType counterc, int amount)
        {
            Amount = amount;
            _pair = new CurrencyPair() { Base = basec, Counter = counterc };
            SourceExchange = exchange;

            LoadRule(exchange, basec, counterc, amount);
        }


        private bool LoadRule(ExchangeType exchange, CurrencyType basec, CurrencyType counterc, int amount)
        {
            var res = false;

            var _context = new BTCDataClassesDataContext();

            var _a = (from acc in _context.GetTable<ALERT_RULE_FLAT>()
                                where (acc.EXCHANGE_ID == (int)exchange
                                                            && acc.BASE_CURRENCY_ID == (int)basec
                                                            && acc.COUNTER_CURRENCY_ID == (int)counterc
                                                            && acc.AMOUNT == amount)
                                select acc).ToList<ALERT_RULE_FLAT>();

            if (null != _a && _a.Count > 0)
            {
                this._id = _a[0].ID;
                this.Amount = _a[0].AMOUNT;
                this._pair = new CurrencyPair() { Base = (CurrencyType)_a[0].BASE_CURRENCY_ID, Counter = (CurrencyType)_a[0].COUNTER_CURRENCY_ID };
                //this._baseCurrencyID = _a[0].BASE_CURRENCY_ID;
                //this._counterCurrencyID = _a[0].COUNTER_CURRENCY_ID;
                this._sourceExchangeID = _a[0].EXCHANGE_ID;

                res = true;
            }

            return res;
        }

        public FlatAmountRule(int ID)
        {
            LoadRule(ID);
        }

        private bool LoadRule(int ID)
        {
            var res = false;

            var _context = new BTCDataClassesDataContext();

            var _a = (from acc in _context.GetTable<ALERT_RULE_FLAT>()
                                where (acc.ID == ID)
                                select acc).ToList<ALERT_RULE_FLAT>();

            if (null != _a && _a.Count > 0)
            {
                this._id = _a[0].ID;
                this.Amount = _a[0].AMOUNT;
                this._pair = new CurrencyPair() { Base = (CurrencyType)_a[0].BASE_CURRENCY_ID, Counter = (CurrencyType)_a[0].COUNTER_CURRENCY_ID };
                this._sourceExchangeID = _a[0].EXCHANGE_ID;

                res = true;
            }

            return res;
        }

        public override void AddAccount(int AccID)
        {
            var _context = new BTCDataClassesDataContext();

            var _rule = (from c in _context.GetTable<ACCOUNT_RULE_FLAT>()
                                                   where (c.RULE_ID == this.ID && c.ACCOUNT_ID == AccID)
                                                   select c).SingleOrDefault();

            if (null == _rule)
            {
                var _acc = GetAccountRuleTable();

                var _a = new ACCOUNT_RULE_FLAT();

                _a.ACCOUNT_ID = AccID;
                _a.RULE_ID = this.ID;

                _acc.InsertOnSubmit(_a);
                _acc.Context.SubmitChanges();
            }
        }

        public override void RemoveAccount(int AccID)
        {
            var _context = new BTCDataClassesDataContext();

            var _rule = (from c in _context.GetTable<ACCOUNT_RULE_FLAT>()
                                      where (c.RULE_ID == this.ID && c.ACCOUNT_ID == AccID)
                                      select c).Single();

            if (null != _rule)
            {
                _context.ACCOUNT_RULE_FLATs.DeleteOnSubmit(_rule);
                _context.SubmitChanges();
            }
        }

        public override List<int> GetAccountIDList()
        {
            var res = new List<int>();

            var _context = new BTCDataClassesDataContext();

            var _l = (from acc in _context.GetTable<ACCOUNT_RULE_FLAT>()
                                where (acc.RULE_ID == _id)
                                select acc).ToList<ACCOUNT_RULE_FLAT>();

            foreach (ACCOUNT_RULE_FLAT _r in _l)
            {
                res.Add(_r.ACCOUNT_ID);
            }

            return res;
        }

        public override bool Test(Tick current)
        {
            var res = false;

            var _previous = TickDAL.GetPreviousTick(this.SourceExchange, current);

            if (null == _previous || _previous.Spot == 0)
            {
                throw new Exception("Unable to retrieve previous tick when attempting to test flat rule (" + this.SourceExchange.ToString() + " - " + this.Pair.Base.ToString() + "/" + this.Pair.Counter.ToString() + ") (" + this.Amount.ToString() + ")");
            }


            if (Amount == current.Spot
                || Amount == _previous.Spot
                || ((Amount <= _previous.Spot && Amount >= current.Spot) ||
                    (Amount >= _previous.Spot && Amount <= current.Spot)))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        private static System.Data.Linq.Table<ACCOUNT_RULE_FLAT> GetAccountRuleTable()
        {
            var _context = new BTCDataClassesDataContext();

            return _context.GetTable<ACCOUNT_RULE_FLAT>();
        }

        private static System.Data.Linq.Table<ALERT_RULE_FLAT> GetAlertRuleTable()
        {
            var _context = new BTCDataClassesDataContext();

            return _context.GetTable<ALERT_RULE_FLAT>();
        }

        public bool Save()
        {
            var res = true;

            var _context = new BTCDataClassesDataContext();

            var _rule = (from c in _context.GetTable<ALERT_RULE_FLAT>()
                                                   where c.ID == this.ID
                                                   select c).SingleOrDefault();

            if (null == _rule)
            {
                var _acc = GetAlertRuleTable();

                var _a = new ALERT_RULE_FLAT();

                _a.EXCHANGE_ID = _sourceExchangeID;
                _a.AMOUNT = Amount;
                _a.COUNTER_CURRENCY_ID = (int)_pair.Counter;
                _a.BASE_CURRENCY_ID = (int)_pair.Base;

                _acc.InsertOnSubmit(_a);
                _acc.Context.SubmitChanges();

                this.ID = _a.ID;
            }
            else
            {
                _rule.EXCHANGE_ID = _sourceExchangeID;
                _rule.COUNTER_CURRENCY_ID = (int)_pair.Counter;
                _rule.BASE_CURRENCY_ID = (int)_pair.Base;
                _rule.AMOUNT = Amount;

                _context.SubmitChanges();
            }


            return res;
        }

        private static List<ALERT_RULE_FLAT> AlertRuleList()
        {
            var _context = new BTCDataClassesDataContext();

            return (from acc in _context.GetTable<ALERT_RULE_FLAT>()
                                    select acc).ToList<ALERT_RULE_FLAT>();
        }

        public static List<FlatAmountRule> GetFlatRuleList()
        {
            var _l = AlertRuleList();

            var res = new List<FlatAmountRule>();

            foreach (ALERT_RULE_FLAT _a in _l)
            {
                res.Add(new FlatAmountRule(_a.ID));
            }

            return res;
        }

        private static List<int> GetRuleIDs(int AcctID)
        {
            var res = new List<int>();

            var _context = new BTCDataClassesDataContext();

            var _l = (from acc in _context.GetTable<ACCOUNT_RULE_FLAT>()
                                where (acc.ACCOUNT_ID == AcctID)
                                select acc).ToList<ACCOUNT_RULE_FLAT>();

            foreach (ACCOUNT_RULE_FLAT _r in _l)
            {
                res.Add(_r.RULE_ID);
            }

            return res;
        }

        public static List<FlatAmountRule> GetListForAccount(int AcctID)
        {
            var _l = AlertRuleList();

            var _ids = GetRuleIDs(AcctID);

            var res = new List<FlatAmountRule>();

            foreach (ALERT_RULE_FLAT _a in _l)
            {
                if (_ids.Contains(_a.ID))
                {
                    res.Add(new FlatAmountRule(_a.ID));
                }
            }

            return res;
        }
    }
}
